package api

import (
	"fmt"

	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
	"github.com/urfave/cli"
)

var (
	store = cookie.NewStore([]byte("lmp_!&&"))
)

const (
	// InternalError  服务器内部错误
	InternalError = iota + 5000

	// IllegalArgument 参数错误
	IllegalArgument

	// DatabaseError 数据库错误
	DatabaseError

	// HTTPError HTTP请求错误
	HTTPError

	// ExternalError 外部接口请求错误
	ExternalError
	// UnmarshalTypeFail 结构解析错误
	UnmarshalTypeFail
	// MarshalTypeFail 结构转换错误
	MarshalTypeFail
	// TypeTranslateFail 类型转化错误
	TypeTranslateFail
	// ValueNotExist 值不存在
	ValueNotExist
)

// ParamConstruct ParamConstruct值类型
type ParamConstruct struct {
	FieldName    string
	DefaultValue interface{}
	CheckValue   []interface{}
	Need         bool
	Link         string
	Symbol       string
}

// NewServer create server
func NewServer(config *cli.Context) *gin.Engine {
	r := gin.Default()

	mode := config.String("mode")
	switch mode {
	case "debug":
		gin.SetMode(gin.DebugMode)
	case "test":
		gin.SetMode(gin.TestMode)
	case "release":
		gin.SetMode(gin.ReleaseMode)
	default:
		gin.SetMode(gin.DebugMode)
	}

	if config.Bool("weblogin") {
		r.Use(sessions.Sessions("lmpsession", store))
		r.Use(func(c *gin.Context) {
			session := sessions.Default(c)
			v := session.Get("loginName")
			if v != nil {
				c.Request.Header.Add("loginName", v.(string))
			} else {
				if c.Request.URL.Path != "/auth/login" {
					c.JSON(401, gin.H{
						"code":    401,
						"message": "not login",
					})
					c.Abort()
					return
				}
			}
		})
	}

	for _, reg := range routerRegisters {
		reg(&RouterGroup{
			routerGroup: &r.RouterGroup,
		})
	}
	return r
}

// SetErrorResponse code message
func SetErrorResponse(c *Context, code int, message string) {
	c.Set("code", code)
	c.JSON(200, gin.H{
		"code":    code,
		"message": message,
	})
}

// SetSuccessResponse data
func SetSuccessResponse(c *Context, data interface{}) {
	c.Set("code", 0)
	c.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    data,
	})
}

// SetResponse data or error
func SetResponse(c *Context, dataOrError ...interface{}) {
	if len(dataOrError) == 0 {
		c.Set("code", 0)
		c.JSON(200, gin.H{
			"code": 0,
			"data": nil,
		})
		return
	}

	if err, ok := dataOrError[0].(*Error); ok {
		c.Set("code", err.Code)
		c.JSON(200, gin.H{
			"code": err.Code,
			"data": err.Message,
		})
		return
	}

	if err, ok := dataOrError[0].(error); ok {
		c.Set("code", 500)
		c.JSON(200, gin.H{
			"code": 500,
			"data": err.Error(),
		})
		return
	}

	c.Set("code", 0)
	c.JSON(200, gin.H{
		"code": 0,
		"data": dataOrError[0],
	})
}

// NewError create server error
func NewError(code int, message string) error {
	return &Error{Code: code, Message: message}
}

// Error server error
type Error struct {
	// Code is The status code generated by the server.
	Code int
	// Message is a human-readable explanation specific to this occurrence of the problem.
	Message string
}

// Error
func (e *Error) Error() string {
	return fmt.Sprintf("%d : %s", e.Code, e.Message)
}

var routerRegisters []func(*RouterGroup)

// SetRouterRegister 设置路由注册器
func SetRouterRegister(reg func(group *RouterGroup)) {
	routerRegisters = append(routerRegisters, reg)
}
